package lab3;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * Mex6 - more threading in GUIs - stopping work threads
 * @author Anthony Varghese
 */

/**
 * Mex6Window - window (JFrame) class for threading
 */
class Mex6Window extends JFrame {
	/**
	 * Data members
	 * serialVersionUID - declaring and assigning a value prevents warning messages.
	 * origTitle - title for the window
	 * jContentPane
	 * jPanel
	 * jButton
	 */
	private static final long serialVersionUID = 1L;
	private String origTitle = new String("Mex6 window");
	private JPanel jContentPane = null;
	private JPanel jPanel = null;
	private JButton jButton = null;
	private JButton endButton = null;
	private int panelwidth = 300;
	private int panelheight = 180;

	/**
	 * Data members describing the bouncing ball
	 */
	private PongBall6 pong;

	/**
	 * This is the default constructor
	 */
	public Mex6Window() {
		super();
		initialize();
	}

	/**
	 * Initialize the MexWindow object
	 * 
	 * @return void
	 */
	private void initialize() {
		/**
		 * Set up a timer to refresh the Pong ball positions
		 */
		final int refreshInterval = 200;
		ActionListener refresh = new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				repaint();
			}
		};
		(new javax.swing.Timer(refreshInterval, refresh)).start();
		
		/**
		 * Initialize the jButton and the endButton
		 */
		if (jButton == null) {
			jButton = new JButton();
			jButton.setText("Start");
			jButton.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					// Fire up a PongBall and have it move.
					pong = new PongBall6( 1 );
					pong.start();
				}
			});
		}
		if (endButton == null) {
			endButton = new JButton();
			endButton.setText("End");
			endButton.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					// Wait for the PongBall to be done.
					pong.stop();
					while (pong.isAlive())
						;
					System.out.println("Done!");
				}
			});
		}

		/**
		 * Initialize the jPanel
		 */
		if (jPanel == null) {
			jPanel = new JPanel();
			jPanel.setLayout(new GridBagLayout());
			jPanel.setMinimumSize(new Dimension(panelwidth, panelheight));
			jPanel.setPreferredSize(new Dimension(panelwidth, panelheight));
			jPanel.setBackground(Color.black);
		}
		/**
		 * Initialize the jContentPane
		 */
		if (jContentPane == null) {
			jContentPane = new JPanel();
			jContentPane.setLayout(new FlowLayout());
			jContentPane.add(jButton, null);
			jContentPane.add(endButton, null);
			jContentPane.add(jPanel, null);
		}
		setContentPane( jContentPane );
		setTitle(origTitle);
		setPreferredSize(new Dimension(400, 300));
		setBounds(new Rectangle(200, 100, 400, 300));
		setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	}

	/*
	 * Need to "remember" the old position so we can erase later
	 */
	private java.awt.Point old;
	
	/*
	 * Paint method for the window
	 * 
	 * @see java.awt.Container#paint(java.awt.Graphics)
	 */
	public void paint(java.awt.Graphics g) {
		super.paint(g);

		/*
		 * Get the window size and change the size of the panel if the user has
		 * resized the window.
		 */
		jPanel.setSize((int)(0.8*getWidth()), (int)(0.8*getHeight()) );
		panelwidth = jPanel.getWidth();
		panelheight = jPanel.getHeight();

		if (pong == null || !pong.isAlive())
			return;
		//System.out.println(pong);

		java.awt.Graphics2D g2d = (java.awt.Graphics2D) jPanel.getGraphics();
		java.awt.Point pos = pong.getLocation();
		int scaled_x;
		int scaled_y;

		/*
		 * Find the relative location in the panel
		 * of the old position and erase the pong ball
		 */
		if (old == null) 
			old = new java.awt.Point();
		else {
			scaled_x = old.x * panelwidth / 100;
			scaled_y = old.y * panelheight / 100;
			g2d.setColor( g2d.getBackground() ); // painting using background == erase
			g2d.fillOval(scaled_x, scaled_y, PongBall6.OVAL_WIDTH, PongBall6.OVAL_HEIGHT);
		}
		
		/*
		 * Find the relative location in the panel
		 * of the new position and draw the pong ball
		 */
		scaled_x = pos.x * panelwidth / 100;
		scaled_y = pos.y * panelheight / 100;
		g2d.setColor( pong.getColor() );
		g2d.fillOval(scaled_x, scaled_y, PongBall6.OVAL_WIDTH, PongBall6.OVAL_HEIGHT);
		old.x = pos.x; old.y = pos.y;
	}
}

/**
 * PongBall6 - Class for the ball that should bounce around
 */
class PongBall6 extends Thread{
	private int id;

	private boolean keep_going = true;
	final static int MAXITERATIONS = 1000;
	private int iteration = 0;	

	private java.awt.Point current_position = new java.awt.Point(50, 50);
	private java.awt.Point previous_position = new java.awt.Point();
	private java.awt.Color color = new java.awt.Color(
			127 + (int) (Math.random() * 128),
			127 + (int) (Math.random() * 128),
			127 + (int) (Math.random() * 128));
	final static int OVAL_WIDTH  = 10;
	final static int OVAL_HEIGHT = 10;
	private long sleepInterval;
	private int x_incr;
	private int y_incr;

	/**
	 * Constructor
	 */
	public PongBall6(int i){
		id = i;
		/*
		 * Set the initial x- and y-speeds to something that is not 0
		 */
		do	x_incr = (int) ((Math.random() - 0.5) * 10); while (x_incr == 0);
		do 	y_incr = (int) ((Math.random() - 0.5) * 10); while (y_incr == 0);
		
		iteration = 0;
		
		final long MAX_SLEEP = 500;
		final long MIN_SLEEP = 300;
		sleepInterval = (long) (Math.random() * MAX_SLEEP) + MIN_SLEEP;
	}
	
	public java.awt.Color getColor() {
		return color;
	}
	/*
	 *  getShape - This is not used but it could be
	 *  To scale to the right size of the window, we need to know
	 *  the panel width and height.
	 */
	public java.awt.geom.Ellipse2D getShape(){
		return new java.awt.geom.Ellipse2D.Double(current_position.x, current_position.y,
													OVAL_WIDTH, OVAL_HEIGHT );
	}
	public java.awt.Point getPreviousLocation() {
		return previous_position;
	}
	public java.awt.Point getLocation() {
		return current_position;
	}
	public void move() {
		// remember the old position
		previous_position.x = current_position.x;
		previous_position.y = current_position.y;
		
		// update new position
		current_position.x = current_position.x + x_incr;
		current_position.y = current_position.y + y_incr;
	}
	
	public String toString(){
		return " Pong ball # " + id + " color: " + color + " at " + current_position;
	}
	private void sleep(){
		try {
			sleep( sleepInterval );
		} catch (InterruptedException e) {
			e.printStackTrace();
		}		
	}
	public void run(){
		while (keep_going && iteration < MAXITERATIONS){
			sleep();
			move();
			iteration++;
		}
	}
}


/*
 * Main class for this program
 */
public class Mex6{
	public static void main(String[] args) {
		(new Mex6Window()).setVisible( true );
	}
}
